"""
主题: 创建可管理的属性
问题: 你想给某个实例attribute增加除访问与修改之外的其他处理逻辑，比如类型检查或合法性验证。
提示 : 
"""

import math


class Person:
    def __init__(self, first_name):
        self.first_name = first_name

    # Getter function
    @property
    def first_name(self):
        return self._first_name

    # Setter function
    @first_name.setter
    def first_name(self, value):
        if not isinstance(value, str):
            raise TypeError('Expected a string')
        self._first_name = value

    # Deleter function (optional)
    @first_name.deleter
    def first_name(self):
        raise AttributeError("Can't delete attribute")

class Person1:
    '''已存在的get和set方法基础上定义property'''
    def __init__(self, first_name):
        self.set_first_name(first_name)

    # Getter function
    def get_first_name(self):
        return self._first_name

    # Setter function
    def set_first_name(self, value):
        if not isinstance(value, str):
            raise TypeError('Expected a string')
        self._first_name = value

    # Deleter function (optional)
    def del_first_name(self):
        raise AttributeError("Can't delete attribute")

    # Make a property from existing get/set methods
    name = property(get_first_name, set_first_name, del_first_name)

class Circle:
    """动态计算的property"""

    def __init__(self, radius):
        self.radius = radius

    @property
    def diameter(self):
        return self.radius ** 2

    @property
    def perimeter(self):
        return 2 * math.pi * self.radius

    @property
    def area(self):
        return math.pi * self.radius ** 2

def recipe1():
    a = Person('Guido')
    print(f"{a.first_name= }")  # Calls the getter

    try:
        a.first_name = 42  # Calls the setter
    except TypeError as e:
        print(e)

    try:
        del a.first_name  # Calls the deleter
    except AttributeError as e:
        print(e)        
    

def recipe2():
    print(f"{Person1.name.fget = }")
    print(f"{Person1.name.fset= }")
    print(f"{Person1.name.fdel= }")

    a = Person1('Guido')
    print(f"{a.get_first_name() = }")  # Calls the getter

    try:
        a.set_first_name(42)  # Calls the setter
    except TypeError as e:
        print(e)

    try:
        a.del_first_name() # Calls the deleter
    except AttributeError as e:
        print(e)    

def recipe3():
    c = Circle(4.0)
    print(f"{vars(c) = }")
    print(f"{c.radius = }")
    print(f"{c.area = }")
    print(f"{c.perimeter = }")
    print(f"{vars(c) = }")

def main():
    print('recipe1'.center(20, '*'))
    recipe1()
    print('recipe2'.center(20, '*'))
    recipe2()    
    print('recipe3'.center(20, '*'))
    recipe3()    


if __name__ == '__main__':
    main()          